/*
 * packager.c
 *
 *  Created on: Jan 7, 2022
 *      Author: soliber
 */
//Includes
#include "wifi.h"
#include "usart.h"


//Define
#define LOG_TAG "packager"

#define SYNC_HEADER "\xAA\xFE\x55"

#define MAX_PACK_LEN 500
#define MAX_PACK_DATA (MAX_PACK_LEN-4)

#define EVT_TX_CPLT (1<<0)


//Vatiables
static osMutexId_t packagerlock = NULL;
static uint8_t packbuf[MAX_PACK_LEN];
static osEventFlagsId_t evt=NULL;


//Function Prototypes
static void packager_lock(void);
static void packager_unlock(void);
static void parser_txcplt_callback(UART_HandleTypeDef *huart);


/**
 * @brief packager加锁
 * @note 如果锁未创建，将会自动创建
 */
static void packager_lock(void)
{
	if(packagerlock == NULL)
	{
		packagerlock = osMutexNew(NULL);
	}
	osStatus_t st;
	st = osMutexAcquire(packagerlock, 5000);
	if(st != osOK)
	{
		log_e("packager lock error:%d",st);
		Error_Handler();
	}
}

/**
 * @brief packager解锁
 */
static void packager_unlock(void)
{
	osStatus_t st;
	st = osMutexRelease(packagerlock);
	if(st!=osOK)
	{
		log_e("packager unlock error:%d",st);
		Error_Handler();
	}
}

/**
 * @brief 发送完成回调
 *
 * @param huart 串口HAL句柄
 */
static void parser_txcplt_callback(UART_HandleTypeDef *huart)
{
	assert(huart == &wifi_uart);
	osEventFlagsSet(evt, EVT_TX_CPLT);
}

/**
 * @brief 按照协议打包数据并发送，一次最多发一包
 *
 * @param data 要发送的数据
 * @param len 数据总长度
 * @param timeout 超时时间
 *
 * @return 实际发送的数据量
 */
uint16_t packager_send(int socketid, uint8_t *data, uint16_t len, uint32_t timeout)
{
	assert(data!=NULL);
	if(len == 0) return 0;

	uint32_t tick = osKernelGetSysTimerCount();

	//实际要发送的数据量
	uint16_t sent = min(len,MAX_PACK_DATA);
	//实际要发送的包长
	uint16_t packlen = sent+4;

	//加锁
	packager_lock();

	//数据打包
	packbuf[0]=0xAA;
	packbuf[1]=0xFE;
	packbuf[2]=0x55;
	packbuf[3]=socketid;
	memcpy(packbuf+4,data,sent);

	//准备发送
	if(evt==NULL)
	{
		evt = osEventFlagsNew(NULL);
	}
	osEventFlagsClear(evt, EVT_TX_CPLT);
	wifi_uart.TxCpltCallback = parser_txcplt_callback;

	//发送
	uint32_t ret;
	uint16_t sent_len;
	while(osKernelGetSysTimerCount()-tick<timeout)
	{
		//启动发送
		ret = HAL_UART_Transmit_DMA(&wifi_uart, packbuf, packlen);
		if(ret == HAL_OK)
		{
			timeout -= osKernelGetSysTimerCount()-tick;

			//开始发送，等待发送完成事件
			ret = osEventFlagsWait(evt, EVT_TX_CPLT, osFlagsWaitAll, timeout);

			//计算已发送数据量
			sent_len = packlen - wifi_uart.hdmatx->Instance->CNDTR;
			sent = (sent_len>4)?sent_len - 4:0;

			//事件错误
			if(ret&osFlagsError)
			{
				//终止传输
				HAL_UART_AbortTransmit(&wifi_uart);
				if(ret == osFlagsErrorTimeout)
				{
					log_e("evt txcplt timeout");
				}
				else
				{
					log_e("evt txcplt error:%d",ret);
					Error_Handler();
				}
			}
			break;
		}
		else
		{
			//出错
			HAL_UART_AbortTransmit(&wifi_uart);
			log_e("tx error:%d",ret);
			Error_Handler();
		}
	};

	//解锁
	packager_unlock();

	return sent;
}
